package device;

import base.UsersBaseInterface;
import device.callbacks.VerifyOnce;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.channels.SocketChannel;
import java.util.*;

class ClockAtomic {
    public int hour;
    public int minute;
    public int second;
    public boolean[] drags;

    public ClockAtomic(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
        this.drags = new boolean[9];
        for (int i = 0; i < 9; ++i) {
            this.drags[i] = false;
        }
    }

    public boolean haveAlarm() {
        return this.hour != -1;
    }

    private String makeDragsMessage() {
        StringBuilder builder = new StringBuilder();
        for (int i = 1; i <= 9; ++i) {
            if (this.drags[i - 1]) {
                builder.append(i);
            }
        }
        if (builder.isEmpty()) {
            builder.append("1");
        }
        return builder.toString();
    }

    public String makeAlarmMessage() {
        return "t=%02d:%02d:%02d,m=%s".formatted(hour, minute, second, makeDragsMessage());
    }
}

class BoxInfo {
    public float tempDown;
    public float tempUp;
    public int humiDown;
    public int humiUp;
    public ClockAtomic[] alarm;

    public BoxInfo(float tempDown, float tempUp, int humiDown, int humiUp) {
        this.tempUp = tempUp;
        this.tempDown = tempDown;
        this.humiUp = humiUp;
        this.humiDown = humiDown;
        this.alarm = new ClockAtomic[4];
        for (int i = 0; i < 4; ++i) {
            this.alarm[i] = new ClockAtomic(-1, -1, -1);
        }
    }

    public String makeBoxMessage() {
        StringBuilder buffer = new StringBuilder();
        buffer.append("u=%.1f,v=%.1f,x=%d,y=%d".formatted(this.tempDown, this.tempUp, this.humiDown, this.humiUp));

        for (int i = 0; i < 4; ++i) {
            if (!alarm[i].haveAlarm()) {
                break;
            }
            buffer.append(",");
            buffer.append(alarm[i].makeAlarmMessage());
        }

        return buffer.toString();
    }

    public void loadRawAlarm(String alarmRaw) {
        // 处理空闹钟的特殊情况
        if ("1".equals(alarmRaw)) {
            for (int i = 0; i < 4; i++) {
                ClockAtomic clock = this.alarm[i];
                clock.hour = -1;
                clock.minute = -1;
                clock.second = -1;
                Arrays.fill(clock.drags, false);
            }
            return;
        }

        // 原有业务逻辑
        String[] alarmStrings = alarmRaw.split("-");
        int num = Math.min(alarmStrings.length, 4);

        for (int i = 0; i < num; i++) {
            String[] parts = alarmStrings[i].split("\\.");
            if (parts.length != 2) continue;

            String[] timeParts = parts[0].split(":");
            if (timeParts.length != 3) continue;

            int hour = Integer.parseInt(timeParts[0]);
            int minute = Integer.parseInt(timeParts[1]);
            int second = Integer.parseInt(timeParts[2]);
            int drugBits = Integer.parseInt(parts[1]);

            ClockAtomic clock = this.alarm[i];
            clock.hour = hour;
            clock.minute = minute;
            clock.second = second;

            for (int j = 0; j < 9; j++) {
                clock.drags[j] = (drugBits & (1 << j)) != 0;
            }
        }

        for (int i = num; i < 4; i++) {
            ClockAtomic clock = this.alarm[i];
            clock.hour = -1;
            clock.minute = -1;
            clock.second = -1;
            Arrays.fill(clock.drags, false);
        }
    }
}

public class MedicineBox extends Device {
    private static final Logger logger = LoggerFactory.getLogger(MedicineBox.class);
    static BoxInfo boxInfo = new BoxInfo(15.0f, 30.0f, 30,50);
    static String alarmRaw = null;
    private String medicineName = null;
    private String preWeight = "0";
    public MedicineBox(SocketChannel socketChannel, UsersBaseInterface users) {
        super(socketChannel, users);
    }

    public void setMedicineName(String medicineName) {
        this.medicineName = medicineName;
    }

    @Override
    public boolean subscribe(Device targetDevice, VerifyOnce verify) {
        super.subscribe(targetDevice);
        return false;
    }

    @Override
    public void update(HashMap<String, String> msgsSet) {
        Collection<String> keySet = msgsSet.keySet();
        for (String key : keySet) {
            String msgValue = msgsSet.get(key);
            if (msgValue != null) {
                String value = keys.get(key);
                if (value != null && !msgValue.equals(value)) {
                    keys.replace(key, msgValue);
                    updateFlag = true;
                }
            }
        }

        String tempDown = msgsSet.get("u");
        if (tempDown != null) {
            boxInfo.tempDown = Float.parseFloat(tempDown);
        }
        String tempUp = msgsSet.get("v");
        if (tempUp != null) {
            boxInfo.tempUp = Float.parseFloat(tempUp);
        }
        String humiDown = msgsSet.get("x");
        if (humiDown != null) {
            boxInfo.humiDown = Integer.parseInt(humiDown);
        }
        String humiUp = msgsSet.get("y");
        if (humiUp != null) {
            boxInfo.humiUp = Integer.parseInt(humiUp);
        }
        String alarmRawFetch = msgsSet.get("alarm");
        if (!Objects.equals(alarmRawFetch, alarmRaw)) {
            if (alarmRawFetch != null) {
                boxInfo.loadRawAlarm(alarmRawFetch);
            }
            alarmRaw = alarmRawFetch;
        }

        String weight = msgsSet.get("weight");
        if (!preWeight.equals(weight)) {
            preWeight = weight;
            logger.info(String.format(Locale.getDefault(), "药品重量: %s g", weight));
        }

        String isTaked = msgsSet.get("taked");
        if (isTaked != null) {
            logger.info(String.format(Locale.getDefault(), "已取药，药名: %s, 剩余药品重量: %s g", this.medicineName, weight));
        }
    }

    @Override
    public void afterRegisterCall() {
        // 立即推送时间信息
        Calendar calendar = Calendar.getInstance();
        String commands = String.format(
                Locale.getDefault(),
                "c=%02d:%02d:%02d,%s",
                calendar.get(Calendar.HOUR_OF_DAY),
                calendar.get(Calendar.MINUTE),
                calendar.get(Calendar.SECOND),
                boxInfo.makeBoxMessage());
        try {
            this.simpleSend(commands);
        } catch (IOException _) {
        }
    }
}
